// package: rewords-server-2024
// filename: mgx
// author: diogoxiang@gmail.com
// time: 2024/7/31 下午2:46

package mgx

import (
	"context"
	"fmt"
	"reflect"

	"go.mongodb.org/mongo-driver/bson"
	"go.mongodb.org/mongo-driver/mongo"

	"rewords-server-2024/internal/dao/cmgox"
	"rewords-server-2024/internal/service"
)

type sMgx struct{}

func NewMgx() *sMgx {
	return &sMgx{}
}
func init() {
	service.RegisterMgx(NewMgx())
}

// InsertOne  插入一个
func (s *sMgx) InsertOne(ctx context.Context, table string, doc interface{}) (err error) {
	err = cmgox.Insert(ctx, table, doc)
	return
}

// InsertMany  插入多个
func (s *sMgx) InsertMany(ctx context.Context, table string, docs interface{}) (err error) {
	// 使用反射将任意切片类型转换为 []interface{}
	val := reflect.ValueOf(docs)
	if val.Kind() != reflect.Slice {
		return fmt.Errorf("docs must be a slice")
	}
	length := val.Len()
	interfaces := make([]interface{}, length)
	for i := 0; i < length; i++ {
		interfaces[i] = val.Index(i).Interface()
	}
	err = cmgox.InsertMany(ctx, table, interfaces)
	return
}

// FindOne  查询一个
func (s *sMgx) FindOne(ctx context.Context, table string, selecter, fields bson.M) (data bson.M, err error) {
	data, err = cmgox.FindOne(ctx, table, ExcludeDeleted(selecter), fields)
	return
}

// Find  查询多个
func (s *sMgx) Find(ctx context.Context, table string, selecter, fields bson.M, page, pageSize int64, sort bson.D) ([]bson.M, error) {
	temp, err := cmgox.Find(ctx, table, ExcludeDeleted(selecter), fields, page, pageSize, sort)
	if err != nil {
		return nil, err
	}
	return temp, nil
}

// FindAndModify  查询一个并修改
func (s *sMgx) FindAndModify(ctx context.Context, table string, selecter bson.M, update interface{}) (*interface{}, error) {
	info, err := cmgox.FindAndModify(ctx, table, selecter, update)
	if err != nil {
		return nil, err
	}

	return &info, nil
}

// FindOneInc  查到一个,并直接修改相应的参数
// 通常用来 做 +1 或是 -1 的某个操作
// 如访问 +1 统计数据+1
func (s *sMgx) FindOneInc(ctx context.Context, table string, selecter bson.M, curKey string) (*interface{}, error) {
	updateBson := bson.M{
		"$inc": bson.M{
			curKey: 1,
		},
	}
	info, err := cmgox.FindAndModify(ctx, table, ExcludeDeleted(selecter), updateBson)
	if err != nil {
		return nil, err
	}
	return &info, nil
}

// UpdateOne  更新一个
func (s *sMgx) UpdateOne(ctx context.Context, table string, selecter bson.M, update interface{}) (result *mongo.UpdateResult, err error) {
	result, err = cmgox.UpdateOne(ctx, table, ExcludeDeleted(selecter), update)
	return
}

// UpdateMany  更新多个
func (s *sMgx) UpdateMany(ctx context.Context, table string, selecter bson.M, update interface{}) (result *mongo.UpdateResult, err error) {
	result, err = cmgox.UpdateMany(ctx, table, ExcludeDeleted(selecter), update)
	return
}

// CountDocuments  计算总数
// 需要设定超时, 如果超时则返回一个 默认的值 100
// 一定要注意, 相应的索引, 如果数据大于100万的时候,统计会非常慢的
func (s *sMgx) CountDocuments(ctx context.Context, table string, selecter bson.M) (count int64, err error) {
	// 删除一些没用的参数, 如分页的
	delete(selecter, "pageSize")
	delete(selecter, "pageNum")

	// 当要统计 整个table 有多少文档的时候用另一个
	if count, err = cmgox.Count(ctx, table, selecter); err != nil {
		return
	}
	return
}

// FindOneAndDecode 查询一个并解码到指定结构
func (s *sMgx) FindOneAndDecode(ctx context.Context, table string, selector, fields bson.M, result interface{}) error {
	data, err := s.FindOne(ctx, table, selector, fields)
	if err != nil {
		return err
	}

	bsonBytes, err := bson.Marshal(data)
	if err != nil {
		return err
	}

	return bson.Unmarshal(bsonBytes, result)
}
